package scatter.schedulequartz.rest.job;

import cn.hutool.core.util.StrUtil;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import scatter.common.rest.tools.InterfaceTool;
import scatter.common.rest.validation.DictService;
import scatter.schedulequartz.pojo.form.NameAndGroupForm;
import scatter.schedulequartz.pojo.record.po.SchedulerRecord;
import scatter.schedulequartz.rest.record.service.ISchedulerRecordService;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 抽象任务封装
 * </p>
 *
 * @author yangwei
 * @since 2021-10-11 14:18
 */
@Slf4j
public abstract class AbstractJob implements Job , InterfaceTool {

	@Autowired
	private ISchedulerRecordService iSchedulerRecordService;
	@Autowired
	private DictService dictService;


	@Override
	public void execute(JobExecutionContext context) throws JobExecutionException {
		log.info("任务执行开始,name={},group={},mergedJobDataMap={}",
				context.getJobDetail().getKey().getName(),
				context.getJobDetail().getKey().getGroup(),
				toJsonStr(context.getMergedJobDataMap()));
		log.info("任务执行 mergedJobDataMap={}",context.getMergedJobDataMap().toString());

		String recordId = null;
		String statusDictId = null;
		String result = null;
		try {

			NameAndGroupForm nameAndGroupForm = new NameAndGroupForm();
			nameAndGroupForm.setName(context.getJobDetail().getKey().getName());
			nameAndGroupForm.setGroup(context.getJobDetail().getKey().getGroup());
			boolean b = iSchedulerRecordService.existRunning(nameAndGroupForm);
			if (b) {
				log.info("任务执行结束，任务尚未执行，因为上一次任务还未结束,name={},group={}",context.getJobDetail().getKey().getName(),context.getJobDetail().getKey().getGroup());
				iSchedulerRecordService.jobConflictOverRecord(context,"任务尚未执行，因为上一次任务还未结束");
				return;
			}
			recordId = iSchedulerRecordService.addStartJobRecord(context);

			result = doExecute(context);
			statusDictId = dictService.getIdByGroupCodeAndValue(SchedulerRecord.SchedulerRecordStatusGroupCode.scheduler_record_status.groupCode(), SchedulerRecord.SchedulerRecordStatusDictItem.success.itemValue());

		}catch (Exception e){
			log.error("任务执行异常",e);
			statusDictId = dictService.getIdByGroupCodeAndValue(SchedulerRecord.SchedulerRecordStatusGroupCode.scheduler_record_status.groupCode(), SchedulerRecord.SchedulerRecordStatusDictItem.fail.itemValue());
			if (StrUtil.isEmpty(result)) {

				if (e instanceof HttpServerErrorException) {

					HttpServerErrorException httpServerErrorException= ((HttpServerErrorException) e);
					HttpResult httpResult = httpResultWrap(httpServerErrorException.getRawStatusCode(), httpServerErrorException.getResponseBodyAsString(), httpServerErrorException.getResponseHeaders());
					result = toJsonStr(httpResult);

				}else if(e instanceof HttpClientErrorException){
					HttpClientErrorException httpClientErrorException = ((HttpClientErrorException)e);
					HttpResult httpResult = httpResultWrap(httpClientErrorException.getRawStatusCode(), httpClientErrorException.getResponseBodyAsString(), httpClientErrorException.getResponseHeaders());
					result = toJsonStr(httpResult);
				}
			}

		}
		finally {
			log.info("任务执行结束,name={},group={}",context.getJobDetail().getKey().getName(),context.getJobDetail().getKey().getGroup());
			if (StrUtil.isEmpty(recordId) || StrUtil.isEmpty(statusDictId)) {
				log.error("这是由于记录执行日志而引起的错误，这很有可能是一个bug");
			}else {
				iSchedulerRecordService.endJobUpdateRecord(recordId,result,statusDictId);
			}
		}
	}

	/**
	 * 任务执行
	 * @param context
	 * @return 返回任务执行结果
	 * @throws JobExecutionException
	 */
	public abstract String doExecute(JobExecutionContext context) throws JobExecutionException;

	/**
	 * http 调用响应结果封装
	 * @param httpStatus
	 * @param body
	 * @param httpHeaders
	 * @return
	 */
	public HttpResult httpResultWrap(int httpStatus, String body, HttpHeaders httpHeaders){
		HttpResult httpResult = new HttpResult();
		httpResult.setStatus(httpStatus);
		httpResult.setBody(body);

		Map<String, Object> responseHeaders = new HashMap<>();
		for (String key : httpHeaders.keySet()) {
			List<String> list = httpHeaders.get(key);
			responseHeaders.put(key, list);
		}
		httpResult.setHeaders(responseHeaders);

		return httpResult;

	}

	@Setter
	@Getter
	public static class HttpResult{
		private int status;
		private String body;
		private Map<String, Object> headers;
	}
}
